package com.easygoods.shiro.realm;

import com.bestvike.stone.core.lang.Convert;
import com.bestvike.stone.core.lang.StringUtils;
import com.bestvike.stone.spring.shiro.auth.Auth;
import com.bestvike.stone.spring.shiro.authc.AuthenticationToken;
import com.bestvike.stone.spring.shiro.authc.exception.AuthenticationException;
import com.bestvike.stone.spring.shiro.authc.exception.account.DisabledAccountException;
import com.bestvike.stone.spring.shiro.authc.exception.account.LockedAccountException;
import com.bestvike.stone.spring.shiro.authc.exception.account.UnknownAccountException;
import com.easygoods.dao.MemberExternalDao;
import com.easygoods.dao.MemberInfoDao;
import com.easygoods.dao.OrderInfoDao;
import com.easygoods.dao.StoreInfoDao;
import com.easygoods.dao.StoreSpuDao;
import com.easygoods.entity.MemberExternal;
import com.easygoods.entity.MemberInfo;
import com.easygoods.entity.StoreInfo;
import com.easygoods.enums.LoginResult;
import com.easygoods.enums.LoginUserType;
import com.easygoods.enums.UserState;
import com.easygoods.service.AuthService;
import com.easygoods.service.MemberService;
import com.easygoods.shiro.auth.UserAuth;
import com.easygoods.shiro.token.ChannelToken;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

/**
 * Created by 许崇雷 on 2019-03-12.
 */
@CommonsLog
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public final class ChannelRealm extends AbstractRealm {
    @Autowired
    private MemberExternalDao memberExternalDao;
    @Autowired
    private MemberInfoDao memberInfoDao;
    @Autowired
    private StoreInfoDao storeInfoDao;
    @Autowired
    private OrderInfoDao orderInfoDao;
    @Autowired
    private StoreSpuDao storeSpuDao;
    @Autowired
    private MemberService memberService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof ChannelToken;
    }

    @Override
    public Auth authenticate(AuthenticationToken token) throws AuthenticationException {
        //三方登陆
        final ChannelToken channelToken = (ChannelToken) token;
        if (!AuthService.hasOpenId(channelToken.getChannel(), channelToken.getOpenId()))
            throw new UnknownAccountException();

        //查询三方用户
        Example externalExample = new Example(MemberExternal.class);
        externalExample.createCriteria().andEqualTo(MemberExternal.EXTERNAL_CHANNEL, channelToken.getChannel().name())
                .andEqualTo(MemberExternal.EXTERNAL_ID, channelToken.getOpenId());
        final MemberExternal memberExternal = this.memberExternalDao.selectOneByExample(externalExample);
        String memberId = memberExternal == null ? null : memberExternal.getMemberId();
        if (memberExternal == null || StringUtils.isBlank(memberId)) {
            this.writeLoginLog(null, null, channelToken.getChannel(), channelToken.getOpenId(), LoginResult.NotExists);
            throw new UnknownAccountException();
        }

        //查询本系统用户
        final MemberInfo memberInfo = this.memberInfoDao.selectByPrimaryKey(memberId);
        if (memberInfo == null) {
            this.writeLoginLog(memberId, null, channelToken.getChannel(), channelToken.getOpenId(), LoginResult.NotExists);
            throw new UnknownAccountException();
        }
        UserState userState = Convert.toType(memberInfo.getState(), UserState.class);
        if (userState != UserState.Normal) {
            this.writeLoginLog(memberInfo.getId(), memberInfo.getMobile(), channelToken.getChannel(), channelToken.getOpenId(), userState.toLoginResult());
            throw new LockedAccountException();
        }

        //查询该用户店铺
        final Example storeExample = new Example(StoreInfo.class);
        storeExample.createCriteria().andEqualTo(StoreInfo.MEMBER_ID, memberId);
        final StoreInfo storeInfo = this.storeInfoDao.selectOneByExample(storeExample);
        final String storeId = storeInfo == null ? null : storeInfo.getId();
        if (storeInfo == null || StringUtils.isBlank(storeId)) {
            log.error(String.format("用户 '%s' 没有 store 信息", memberInfo.getId()));
            this.writeLoginLog(memberId, memberInfo.getMobile(), channelToken.getChannel(), channelToken.getOpenId(), userState.toLoginResult());
            throw new DisabledAccountException();
        }
        //查询店铺收藏,是否创建过订单
        final boolean isStoreSpuExist = this.storeSpuDao.isStoreSpuExist(storeId);
        final boolean isOrderInfoExist = this.orderInfoDao.isOrderInfoExist(memberId);
        //redis 记录 token
        final UserAuth userAuth = UserAuth.loginSuccess(channelToken.getChannel(), channelToken.getOpenId(), memberInfo, isStoreSpuExist || isOrderInfoExist ? LoginUserType.OldUser : LoginUserType.NewUser);
        if (StringUtils.isNotBlank(channelToken.getNickName()))
            userAuth.setNickName(channelToken.getNickName());
        //更新昵称,头像
        this.memberService.modifyMemberInfo(memberId, channelToken.getNickName(), channelToken.getAvatarType(), channelToken.getAvatar());
        //返回
        this.writeLoginLog(memberId, memberInfo.getMobile(), channelToken.getChannel(), channelToken.getOpenId(), LoginResult.Success);
        return userAuth;
    }
}
